/**
 * Copyright (c) 2015-2017, Henry Yang 杨勇 (gismail@foxmail.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.lambkit.module.cms.rpc.service.impl;

import java.util.Date;
import java.util.List;

import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;

import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.SqlPara;
import com.lambkit.module.cms.Cms;
import com.lambkit.module.cms.core.km.CmsScore;
import com.lambkit.module.cms.core.km.MahoutRecommender;
import com.lambkit.module.cms.rpc.api.CmsScoreService;
import com.lambkit.module.cms.rpc.model.CmsArticle;
import com.lambkit.module.cms.rpc.model.CmsFile;
import com.lambkit.module.cms.rpc.model.CmsPage;

/**
 * @author yangyong
 * @website: www.lambkit.com
 * @email: gismail@foxmail.com
 * @date 2020-02-23
 * @version 1.0
 * @since 1.0
 */
public class CmsScoreServiceImpl implements CmsScoreService {
	
	@Override
	public CmsScore findScore(Long userId, Long itemId, CmsScore.Type type) {
		String table = "cms_" + type.name() + "_score";
		Record r = Cms.db().findFirst("select * from " + table + " where user_id=? and item_id=?", userId, itemId);
		return r==null ? null : new CmsScore(r);
	}
	
	@Override
	public void addFileScore(Long userId, Long fileId, Long dScore) {
		// TODO Auto-generated method stub
		CmsScore crs = findScore(userId, fileId, CmsScore.Type.file);
		String tableName = "cms_file_score";
		if(crs==null) {
			crs = new CmsScore(userId, fileId, dScore, new Date());
			Cms.db().save(tableName, "user_id,item_id", crs);
		} else {
			crs.setScore(crs.getScore() + dScore);
			Cms.db().update(tableName, "user_id,item_id", crs);
		}
	}

	@Override
	public void addArticleScore(Long userId, Long articleId, Long dScore) {
		// TODO Auto-generated method stub
		CmsScore crs = findScore(userId, articleId, CmsScore.Type.article);
		String tableName = "cms_article_score";
		if(crs==null) {
			crs = new CmsScore(userId, articleId, dScore, new Date());
			Cms.db().save(tableName, "user_id,item_id", crs);
		} else {
			crs.setScore(crs.getScore() + dScore);
			Cms.db().update(tableName, "user_id,item_id", crs);
		}
	}

	@Override
	public void addPageScore(Long userId, Long pageId, Long dScore) {
		// TODO Auto-generated method stub
		CmsScore crs = findScore(userId, pageId, CmsScore.Type.page);
		String tableName = "cms_page_score";
		if(crs==null) {
			crs = new CmsScore(userId, pageId, dScore, new Date());
			Cms.db().save(tableName, "user_id,item_id", crs);
		} else {
			crs.setScore(crs.getScore() + dScore);
			Cms.db().update(tableName, "user_id,item_id", crs);
		}
	}

	@Override
	public List getScoreList(Long userId, int recomNum, CmsScore.Type type) {
		// TODO Auto-generated method stub
		SqlPara sqlPara = null;
		StringBuilder sb = new StringBuilder("select * from ");
		sb.append(getItemSQL(type));
		sb.append(" in (");
		try {
			List<RecommendedItem> recomList = MahoutRecommender.UserCFRcommender(userId, recomNum, type);
			for(int i = 0;i<recomList.size();i++){
				if(sqlPara==null) {
					sqlPara = new SqlPara();
				}
				Long itemId = recomList.get(i).getItemID();
				if(i>0) sb.append(",");
				sb.append("?");
				sqlPara.addPara(itemId);
			}
			sb.append(")");
		} catch (TasteException e) {
			e.printStackTrace();
		}
		if(sqlPara!=null)  {
			return getItemDataList(sqlPara, type);
		} else {
			return null;
		}
	}

	@Override
	public List getScoreListByItemCF(Long userId, int recomNum, CmsScore.Type type) {
		// TODO Auto-generated method stub
		SqlPara sqlPara = null;
		StringBuilder sb = new StringBuilder("select * from ");
		sb.append(getItemSQL(type));
		sb.append(" in (");
		try {
			List<RecommendedItem> recomList = MahoutRecommender.ItemCFRecommender(userId, recomNum, type);
			for(int i = 0;i<recomList.size();i++){
				if(sqlPara==null) {
					sqlPara = new SqlPara();
				}
				Long itemId = recomList.get(i).getItemID();
				if(i>0) sb.append(",");
				sb.append("?");
				sqlPara.addPara(itemId);
			}
			sb.append(")");
		} catch (TasteException e) {
			e.printStackTrace();
		}
		if(sqlPara!=null)  {
			return getItemDataList(sqlPara, type);
		} else {
			return null;
		}
	}

	@Override
	public List getScoreListBySlopOne(Long userId, int recomNum, CmsScore.Type type) {
		// TODO Auto-generated method stub
		SqlPara sqlPara = null;
		StringBuilder sb = new StringBuilder("select * from ");
		sb.append(getItemSQL(type));
		sb.append(" in (");
		try {
			List<RecommendedItem> recomList = MahoutRecommender.SlopOneRecommender(userId, recomNum, type);
			for(int i = 0;i<recomList.size();i++){
				if(sqlPara==null) {
					sqlPara = new SqlPara();
				}
				Long itemId = recomList.get(i).getItemID();
				if(i>0) sb.append(",");
				sb.append("?");
				sqlPara.addPara(itemId);
			}
			sb.append(")");
		} catch (TasteException e) {
			e.printStackTrace();
		}
		if(sqlPara!=null)  {
			return getItemDataList(sqlPara, type);
		} else {
			return null;
		}
	}
	
	private String getItemSQL(CmsScore.Type type) {
		switch (type) {
		case article:
			return CmsArticle.service().getTableName() + " where article_id ";
		case file:
			return CmsFile.service().getTableName() + " where file_id ";
		case page:
			return CmsPage.service().getTableName() + " where page_id ";
		default:
			return null;
		}
	}
	
	private List getItemDataList(SqlPara sqlPara, CmsScore.Type type) {
		switch (type) {
		case article:
			return CmsFile.service().dao().find(sqlPara);
		case file:
			return CmsFile.service().dao().find(sqlPara);
		case page:
			return CmsPage.service().dao().find(sqlPara);
		default:
			return null;
		}
	}
}
